home *** CD-ROM | disk | FTP | other *** search
/ MacWorld UK 2000 March / MW_UK_2000_03.iso / Shareware World / Utilities / Text Processing / Alpha / Tcl / Modes / tclMode.tcl < prev   
Encoding:
Text File  |  1999-11-21  |  34.9 KB  |  1,119 lines  |  [TEXT/ALFA]

  1. ## -*-Tcl-*-
  2.  # # ###################################################################
  3.  #  Alpha - new Tcl folder configuration
  4.  # 
  5.  #  FILE: "tclMode.tcl"
  6.  #                                    created: 5/4/97 {9:31:10 pm} 
  7.  #                                last update: 21/11/1999 {2:13:29 pm} 
  8.  #  Author: Vince Darley
  9.  #  E-mail: <vince@santafe.edu>
  10.  #    mail: Division of Engineering and Applied Sciences, Harvard University
  11.  #          Oxford Street, Cambridge MA 02138, USA
  12.  #     www: <http://www.santafe.edu/~vince/>
  13.  #  
  14.  # Copyright (c) 1997-1999 Vince Darley
  15.  #  
  16.  # Three procs from original: Tcl::DblClick listArray, getVarValue
  17.  #    
  18.  # Adds support for Tk, Itcl keywords and completions, plus 
  19.  # numerous fixes, improvements and integration with Vince's
  20.  # Additions.
  21.  # ###################################################################
  22.  ##
  23.  
  24. alpha::mode Tcl 1.7.7 tclMenu {*.tcl *.itcl *.itk *.tbc} {
  25.     tclMenu electricTab electricReturn electricBraces
  26. } {
  27.     addMenu tclMenu "•269" "Tcl"
  28.     set unixMode(wish) {Tcl}
  29.     set unixMode(tclsh) {Tcl}
  30.     set unixMode(itclsh) {Tcl}
  31.     set unixMode(itkwish) {Tcl}
  32.     set unixMode(prowish) {Tcl}
  33.     set unixMode(protclsh) {Tcl}
  34.     ensureset tclshSig "WIsH"
  35.     ensureset evaluateRemotely 0
  36.     trace variable evaluateRemotely w evaluateRemoteSynchronise
  37. } maintainer {
  38.     "Vince Darley" vince@santafe.edu <http://www.santafe.edu/~vince/>
  39. } uninstall this-file help {
  40.     This mode is for editing Tcl code.  You can edit code for internal
  41.     use with Alpha, or use Alpha as an external editor for code destined
  42.     for use with Tcl and Tk interpreters --- Sun distributes the Wish
  43.     application and a tcl-tk browser plugin.
  44.     
  45.     You can 'evaluate' a procedure (or any Tcl code for that matter) to 
  46.     make changes on the fly.  If you select 'Evaluate Remotely' in the 
  47.     tcl-tk submenu, then such actions will actually send the code
  48.     to a separately running Wish application to be evaluated.
  49. }
  50.  
  51.  
  52. proc tclMenu {} {}
  53.  
  54. # ◊◊◊◊ menu and prefs ◊◊◊◊ #
  55. # The menu.
  56. proc menu::buildtclMenu {} {
  57.     global tclMenu evaluateRemotely
  58.     set ma [list \
  59.       "/Levaluate" "/-<UswitchToTclsh" \
  60.       [list Menu -n "tcl-tk" -p tcltk::menuProc [list \
  61.       "![lindex {{ } •} $evaluateRemotely]evaluateRemotely" \
  62.       executeCommand]] \
  63.       "(-" "/L<O<BreloadProc" "/I<O<BreformatProc" \
  64.       "/Z<O<BtraceThisProc" "/Z<O<UtraceTclProc…" \
  65.       "/D<O<UdumpTraces" "(-" "rebuildTclIndices" "(-" \
  66.       "<U/PfindProcDefinition…" "/Q<IquickFindProc…" "getVarValue…" \
  67.       "insertMenuCodes…" "insertBindingCodes…" "/4<BaddRemoveDollars" \
  68.       "/3<BinsertDivider" "/8<I<BsurroundWithBullets"]
  69.     return [list build $ma Tcl::MenuProc "" $tclMenu]
  70. }
  71. menu::buildProc tclMenu menu::buildtclMenu
  72. menu::buildSome tclMenu
  73.  
  74. newPref v prefixString {# } Tcl
  75. newPref f wordWrap {0} Tcl
  76. newPref v funcExpr {^proc *([+-a-zA-Z0-9]+)} Tcl
  77. newPref v parseExpr {^proc *([+-a-zA-Z0-9]+)} Tcl
  78. newPref v wordBreak {(\$)?[\w:_]+} Tcl
  79. newPref v wordBreakPreface {([^\w:_\$]|.\$)} Tcl
  80. newPref f autoMark 0 Tcl
  81. newPref v stringColor green Tcl
  82. newPref v commentColor red Tcl
  83. newPref v keywordColor blue Tcl
  84. # Colour to use for Alpha's built in commands
  85. newPref v alphaKeyWordColor    none Tcl stringColorProc
  86. # Colour Tk commands
  87. newPref f recogniseTk 1 Tcl Tcl::_updateKeywords
  88. # Colour [incr Tcl] commands
  89. newPref f recogniseItcl 1 Tcl Tcl::_updateKeywords
  90. # Recognise and colour some common procedures 'lunion' etc.
  91. newPref f recognisePseudoTcl 1 Tcl Tcl::_updateKeywords
  92. # Indentation scheme for lines following one ending in a backslash
  93. newPref v indentSlashEndLines 1 Tcl "" indent::amounts varindex
  94. # Mark files structurally, recognising the special comments
  95. # entered by 'ctrl-3'
  96. newPref f structuralMarks 0 Tcl
  97. set Tcl::startPara {^(.*\{)?[ \t]*(#|$)}
  98. set Tcl::endPara {^(.*\})?[ \t]*(#|$)}
  99. set Tcl::commentRegexp {^[ \t]*#}
  100.  
  101. ## 
  102.  # -------------------------------------------------------------------------
  103.  # 
  104.  # "Tcl::_updateKeywords" --
  105.  # 
  106.  #  This proc now includes support for optional separate colorization of 
  107.  #  alpha commands. To use, set 'alphaKeyWordColor' to something other than 
  108.  #  'none' in the Tcl Mode Preferences dialog. -trf
  109.  # -------------------------------------------------------------------------
  110.  ##
  111.  
  112.  
  113. proc Tcl::_updateKeywords {args} {
  114.     # all except beep and echo are basic Tcl keywords
  115.     set tclKeyWords {
  116.     after append array auto_execok auto_import auto_load
  117.     auto_load_index auto_qualify beep binary break case catch cd clock
  118.     close concat continue dde default echo else elseif encoding eof
  119.     error eval exec exit expr fblocked fconfigure fcopy file
  120.     fileevent flush for foreach format gets glob global history if
  121.     incr info interp join lappend lindex linsert list llength load
  122.     lrange lreplace lsearch lsort namespace open package pid
  123.     pkg_mkIndex proc puts pwd read regexp regsub rename resource
  124.     return scan seek set socket source split string subst switch
  125.     tclLog tclMacPkgSearch tclPkgSetup tclPkgUnknown tell time
  126.     trace unknown unset update uplevel upvar variable vwait while
  127.     }
  128.  
  129.     set alphaKeyWords {
  130.     abortEm abbrev addAlphaChars addMenuItem 
  131.     AEBuild alertnote alphaHelp ascii askyesno backColor backSpace 
  132.     backwardChar backwardCharSelect backwardDeleteWord 
  133.     backwardWord balance beginningBufferSelect beginningLineSelect 
  134.     beginningOfBuffer beginningOfLine Bind blink breakIntoLines 
  135.     bringToFront buttonAlert capitalizeRegion capitalizeWord 
  136.     centerRedraw clear closeAll colors colorTriple copy cp 
  137.     createTagFile createTMark currentPosition cut decToHex 
  138.     deleteChar deleteMenuItem deleteModeBindings deleteSelection 
  139.     deleteWord describeBinding deleteText dialog dirs display 
  140.     displayMode dosc downcaseRegion downcaseWord dumpColors 
  141.     dumpMacro edit enableMenuItem endBufferSelect endKeyboardMacro 
  142.     endLineSelect endOfBuffer endOfLine enterSelection evaluate
  143.     eventHandler exchangePointAndMark execAbbrev execute 
  144.     executeKeyboardMacro fileInfo fileRemove find findAgain 
  145.     findAgainBackward findFile findInNextFile findTag float 
  146.     floatShowHide forwardChar forwardCharSelect forwardWord 
  147.     freeMem get_directory getAscii getChar getModifiers getColors 
  148.     getfile getFileInfo getGeometry getline getMainDevice getMark 
  149.     getNamedMarks getPathName getPos getScrap getSelect getText 
  150.     getTMarks getWinInfo goto gotoMark gotoTMark hexToDec icon 
  151.     icURL icGetPref icOpen insertAscii insertColorEscape 
  152.     insertFile insertMenu insertPathName insertText insertToTop 
  153.     isearch iterationCount jumpToRegister keyAscii keyCode 
  154.     killLine killWindow largestPrefix launch lineStart 
  155.     listBindings listpick lookAt markHilite markMenuItem 
  156.     matchBrace matchIt maxPos Menu message minPos mkdir mousePos 
  157.     moveInsertionHere moveFile moveWin mtime nameFromAppl new newPref
  158.     nextLine nextLineSelect nextLineStart nextSentence nextWindow 
  159.     now oneSpace openLine otherPane pageBack pageForward pageSetup 
  160.     paste pointToRegister popd posToRowCol prefixChar previousLine 
  161.     prevLineSelect prevSentence prevWindow print processes prompt 
  162.     pushd putfile putScrap quit rectMarkHilite redo 
  163.     regModeKeywords removeFile removeMark 
  164.     removeMenu removeTMark replace replaceAll replace&FindAgain 
  165.     replaceString replaceText restoreVars revert rmdir rowColToPos 
  166.     rsearch save saveAs saveVars scrollDownLine scrollLeftCol 
  167.     scrollRightCol scrollUpLine search searchString select selEnd 
  168.     sendOpenEvent sendToBack setFileInfo setFontsTabs setMark 
  169.     setNamedMark setWinInfo shell shiftLeftRegion shiftRightRegion 
  170.     sizeWin sortMarks spacesToTabs specToPathName splitWindow 
  171.     startEscape startKeyboardMacro statusPrompt substituteVars 
  172.     switchTo tab tabsToSpaces tclFileCompletion  
  173.     thinkReference ticks toggleScrollbar traceFunc unascii unBind 
  174.     undo unfloat upcaseRegion upcaseWord version watchCursor wc 
  175.     winNames wrap wrapText xtclcmd yank zapInvisibles zoom
  176.     }
  177.     
  178.     set tkKeyWords {
  179.     bell bind bindtags button canvas checkbutton console destroy
  180.     entry event focus font frame grab grid image label listbox menu
  181.     menubutton message pack place radiobutton raise scale scrollbar
  182.     text tk tkwait toplevel winfo wm
  183.     }
  184.     
  185.     set itclKeyWords {
  186.     @scope body class code common component configbody constructor
  187.     define destructor hull import inherit itcl itk itk_component
  188.     itk_initialize itk_interior itk_option iwidgets keep method
  189.     private protected public
  190.     }
  191.     global TclmodeVars
  192.     # add Tk keywords
  193.     if {$TclmodeVars(recogniseTk)} {
  194.     set tclKeyWords [concat $tclKeyWords $tkKeyWords]
  195.     }
  196.     # add the [incr tcl] keywords
  197.     if {$TclmodeVars(recogniseItcl)} {
  198.     set tclKeyWords [concat $tclKeyWords $itclKeyWords]
  199.     }
  200.     if {$TclmodeVars(recognisePseudoTcl)} {
  201.     set tclKeyWords [concat $tclKeyWords "lunion lreverse lremove lunique car"]
  202.     }
  203.     # add user extras
  204.     global Tclwords
  205.     if {[info exists Tclwords]} {
  206.     set tclKeyWords [concat $tclKeyWords $Tclwords]
  207.     }
  208.     global Tclcmds
  209.     set Tclcmds { append array catch close concat continue elseif error
  210.     for foreach format lindex llength lrange lreplace lsearch lsort regexp 
  211.     regsub rename return string switch while }
  212.     if {$TclmodeVars(recogniseTk)} {
  213.     append Tclcmds {
  214.         tkButtonDown tkButtonEnter tkButtonInvoke tkButtonLeave 
  215.         tkButtonUp tkCancelRepeat tkCheckRadioInvoke tkDarken 
  216.         tkEntryAutoScan tkEntryBackspace tkEntryButton1 
  217.         tkEntryClosestGap tkEntryInsert tkEntryKeySelect 
  218.         tkEntryMouseSelect tkEntryNextWord tkEntryPaste 
  219.         tkEntryPreviousWord tkEntrySeeInsert tkEntrySetCursor 
  220.         tkEntryTranspose tkEventMotifBindings tkFDGetFileTypes 
  221.         tkFirstMenu tkFocusGroup_BindIn tkFocusGroup_BindOut 
  222.         tkFocusGroup_Create tkFocusGroup_Destroy tkFocusGroup_In 
  223.         tkFocusGroup_Out tkFocusOK tkListboxAutoScan 
  224.         tkListboxBeginExtend tkListboxBeginSelect tkListboxBeginToggle 
  225.         tkListboxCancel tkListboxDataExtend tkListboxExtendUpDown 
  226.         tkListboxMotion tkListboxSelectAll tkListboxUpDown tkMbButtonUp 
  227.         tkMbEnter tkMbLeave tkMbMotion tkMbPost tkMenuButtonDown 
  228.         tkMenuDownArrow tkMenuDup tkMenuEscape tkMenuFind 
  229.         tkMenuFindName tkMenuFirstEntry tkMenuInvoke tkMenuLeave 
  230.         tkMenuLeftArrow tkMenuMotion tkMenuNextEntry tkMenuNextMenu 
  231.         tkMenuRightArrow tkMenuUnpost tkMenuUpArrow tkMessageBox 
  232.         tkPostOverPoint tkRecolorTree tkRestoreOldGrab tkSaveGrabInfo 
  233.         tkScaleActivate tkScaleButton2Down tkScaleButtonDown 
  234.         tkScaleControlPress tkScaleDrag tkScaleEndDrag tkScaleIncrement 
  235.         tkScreenChanged tkScrollButton2Down tkScrollButtonDown 
  236.         tkScrollButtonUp tkScrollByPages tkScrollByUnits tkScrollDrag 
  237.         tkScrollEndDrag tkScrollSelect tkScrollStartDrag tkScrollToPos 
  238.         tkScrollTopBottom tkTabToWindow tkTearOffMenu tkTextAutoScan 
  239.         tkTextButton1 tkTextClosestGap tkTextInsert tkTextKeyExtend 
  240.         tkTextKeySelect tkTextNextPara tkTextNextPos tkTextNextWord 
  241.         tkTextPaste tkTextPrevPara tkTextPrevPos tkTextResetAnchor 
  242.         tkTextScrollPages tkTextSelectTo tkTextSetCursor 
  243.         tkTextTranspose tkTextUpDownLine tkTraverseToMenu 
  244.         tkTraverseWithinMenu tk_bisque tk_chooseColor tk_dialog 
  245.         tk_focusFollowsMouse tk_focusNext tk_focusPrev tk_getOpenFile 
  246.         tk_getSaveFile tk_messageBox tk_optionMenu tk_popup 
  247.         tk_setPalette tk_textCopy tk_textCut tk_textPaste
  248.     }
  249.     }
  250.     
  251.     if {$TclmodeVars(recogniseTk)} {
  252.     regModeKeywords -e {#} -c $TclmodeVars(commentColor) \
  253.       -s $TclmodeVars(stringColor) \
  254.       -k $TclmodeVars(keywordColor) Tcl $tclKeyWords 
  255.     # add this line if we can handle double 'magic chars'
  256.     #-m {tk} 
  257.     } else {
  258.     regModeKeywords -e {#} -c $TclmodeVars(commentColor) \
  259.       -s $TclmodeVars(stringColor) \
  260.       -k $TclmodeVars(keywordColor) Tcl $tclKeyWords 
  261.     }
  262.     if {$TclmodeVars(alphaKeyWordColor) != "none"} {
  263.     regModeKeywords -a -k $TclmodeVars(alphaKeyWordColor) Tcl $alphaKeyWords
  264.     }
  265. }
  266. # call it now
  267. Tcl::_updateKeywords
  268.  
  269. proc Tcl::MenuProc {menu item} {
  270.     switch -glob $item {
  271.     "traceThisProc" {
  272.         procs::traceProc [procs::findEnclosingName [getPos]]
  273.     }
  274.     "reformatProc" {
  275.         procs::reformatEnclosing [getPos]
  276.     }
  277.     "reloadProc" {
  278.         procs::loadEnclosing [getPos]
  279.     }
  280.     "findProcDefinition" {
  281.         procs::findDefinition
  282.     }
  283.     "quickFindProc" {
  284.         # use the status line
  285.         procs::quickFindDefn
  286.     }
  287.     "switch*" {
  288.         set v "[string tolower [string range $item 8 end]]Sig"
  289.         global $v
  290.         app::launchFore [set $v]
  291.     }
  292.     "addRemoveDollars" {
  293.         togglePrefix \$
  294.     }
  295.     default {
  296.         menu::generalProc Tcl $item 0
  297.     }
  298.     }
  299. }
  300. namespace eval tcltk {}
  301.  
  302. proc tcltk::menuProc {menu item} {
  303.     switch -- $item {
  304.     "evaluateRemotely" {
  305.         global evaluateRemotely
  306.         set evaluateRemotely [expr {1 - $evaluateRemotely}]
  307.     }
  308.     default {
  309.         global tclshSig
  310.         set cmd [getline "Please enter the script to send to tcl-tk"]
  311.         if {$cmd == ""} {return}
  312.         if {$tcl_platform(platform) == "macintosh"} {
  313.         set res [AEBuild -r -t 30000 '$tclshSig' misc dosc ---- "“$cmd”"]
  314.         } else {
  315.         set res [tcltk::evaluate $cmd]
  316.         }
  317.         alertnote "Result was '$res'"
  318.     }
  319.     }
  320. }
  321.  
  322. proc evaluateRemoteSynchronise {args} {
  323.     global evaluateRemotely tclMenu
  324.     catch {markMenuItem "tcl-tk" evaluateRemotely $evaluateRemotely}
  325.     if {$evaluateRemotely} {
  326.     if {[info commands notRemoteEvaluate] == ""} {
  327.         rename evaluate notRemoteEvaluate
  328.         ;proc evaluate {} {remoteEvaluate}
  329.     }
  330.     menu::replaceRebuild tclMenu "•320"
  331.     } else {
  332.     if {[info commands notRemoteEvaluate] != ""} {
  333.         rename evaluate {}
  334.         rename notRemoteEvaluate evaluate
  335.     }
  336.     menu::replaceRebuild tclMenu "•269"
  337.     }
  338. }
  339.  
  340.  
  341. proc remoteEvaluate {} {
  342.     message "Remote reply: [tcltk::evaluate [getSelect]]"
  343. }
  344.  
  345. proc tcltk::evaluate {what} {
  346.     global tclshSig tcl_platform
  347.     if {$tcl_platform(platform) == "macintosh"} {
  348.     app::ensureRunning $tclshSig
  349.     if {[catch {set r [aebuild::result -t 30000 '${tclshSig}' misc \
  350.       dosc ---- [aebuild::TEXT $what]]} res]} {
  351.         set res "Error: $res"
  352.     }
  353.     #catch {dosc -c '${tclshSig}' -s $what} res
  354.     #return $res
  355.     } else {
  356.     global tclshInterp
  357.     if {![info exists tclshInterp]} {
  358.         if {[catch {tcltk::findTclshInterp}]} {
  359.         return "No shell selected"
  360.         }
  361.     }
  362.     if {$tcl_platform(platform) == "windows"} {
  363.         if {[dde services TclEval $tclshInterp] == ""} {
  364.         alertnote "The remote shell has died, please select a new one."
  365.         unset tclshInterp
  366.         return [tcltk::evaluate $what]
  367.         }
  368.         dde execute TclEval $tclshInterp [list catch $what alpha_result]
  369.         return [dde request TclEval $tclshInterp alpha_result]
  370.     } else {
  371.         catch {send $tclshInterp $what} res
  372.     }
  373.     }
  374.     return $res
  375. }
  376.  
  377. proc tcltk::listInterps {} {
  378.     global tcl_platform
  379.     if {$tcl_platform(platform) == "windows"} {
  380.     set res {}
  381.     foreach service [dde services TclEval ""] {
  382.         lappend res [lindex $service 1]
  383.     }
  384.     return $res
  385.     } else {
  386.     return [winfo interps]
  387.     }
  388. }
  389.  
  390. proc tcltk::findTclshInterp {} {
  391.     global tclshInterp tclshSigs tclshSig
  392.     set old [tcltk::listInterps]
  393.     set shel [listpick -p "Use which Tcl shell?" [concat $old \
  394.       [list "------------------" "Launch new shell"]]]
  395.     if {$shel == "Launch new shell"} {
  396.     global tcl_platform HOME
  397.     if {$tcl_platform(platform) == "windows"} {
  398.         app::runScript tclsh "Tcl shell" [file join $HOME Tools winRemoteShell.tcl] 1
  399.     } else {
  400.         app::launchElseTryThese $tclshSigs tclshSig "Please locate the remote Tcl application"
  401.     }
  402.     while {[tcltk::listInterps] == $old} {
  403.         update
  404.     }
  405.     set tclshInterp [lremove -l [tcltk::listInterps] $old]
  406.     # We're left with two items
  407.     set tclshInterp [lindex $tclshInterp 0]
  408.     } else {
  409.     set tclshInterp $shel
  410.     }
  411. }
  412.  
  413. # ◊◊◊◊ Quick Find Proc… ◊◊◊◊ #
  414.  
  415. proc procs::quickFindDefn {} {
  416.     Tcl::DblClickHelper [prompt::statusLineComplete "proc" procs::complete]
  417. }
  418.  
  419. if {[info tclversion] < 8.0} {
  420.     proc procs::complete {pref} {
  421.     return [info commands ${pref}*]
  422.     }
  423. } else {
  424.     proc procs::complete {pref} {
  425.     if {[regexp {(.*)([^:]+)$} $pref "" start tail]} {
  426.         set cmds [info commands ${pref}*]
  427.         foreach child [namespace children ::$start] {
  428.         if {[string match "::${tail}*" $child]} {
  429.             foreach cmd [info commands ${start}${child}::*] {
  430.             lappend cmds [string trimleft $cmd :]
  431.             }
  432.         }
  433.         }
  434.         return $cmds
  435.     } else {
  436.         return [info commands ${pref}*]
  437.     }
  438.     }
  439. }
  440.  
  441. # ◊◊◊◊ electric behaviour ◊◊◊◊ #
  442. proc Tcl::electricLeft {} {
  443.     if {[literalChar]} { insertText "\{"; return }
  444.     set pat "\}\[ \t\r\n\]*(else(if)?)\[ \t\r\n\]*\$"
  445.     set p [getPos]
  446.     if { [set res [findPatJustBefore "\}" "$pat" $p word]] == "" } { 
  447.     insertText "\{"
  448.     return
  449.     }
  450.     # we have an if/else(if)/else
  451.     switch -- $word {
  452.     "else" {
  453.         replaceText [lindex $res 0] $p "\} $word \{\r"
  454.         bind::IndentLine
  455.     }
  456.     "elseif" {
  457.         replaceText [lindex $res 0] $p "\} $word \{"
  458.     }
  459.     }
  460. }
  461.     
  462. proc Tcl::electricRight {} {
  463.     if {[literalChar]} { insertText "\}"; return }
  464.     set p [getPos]
  465.     if { [regexp "\[^ \t\]" [getText [lineStart $p] $p]] } {
  466.     insertText "\}"
  467.     blink [matchIt "\}" [pos::math $p - 1]]
  468.     return
  469.     }
  470.     set start [lineStart $p]
  471.     insertText "\}"
  472.     createTMark tcl_er [getPos]
  473.     backwardChar
  474.     bind::IndentLine
  475.     gotoTMark tcl_er ; removeTMark tcl_er
  476.     bind::CarriageReturn
  477.     blink [matchIt "\}" [pos::math $start - 1]]
  478. }
  479.  
  480. ## 
  481.  # -------------------------------------------------------------------------
  482.  # 
  483.  # "Tcl::correctIndentation" --
  484.  # 
  485.  #  Returns the correct indentation for the line containing $pos, if that
  486.  #  line were to contain ordinary characters only.  It is the 
  487.  #  responsibility of the calling procedure to ensure that if we are to
  488.  #  insert/have a line already, that that information is taken into
  489.  #  account, by passing in the argument 'next'
  490.  # -------------------------------------------------------------------------
  491.  ##
  492. proc Tcl::correctIndentation {pos {next ""}} {
  493.     global indent_amounts indentSlashEndLines
  494.     # preliminaries
  495.     if {[pos::compare [set beg [lineStart $pos]] == [minPos]]} { return 0 }
  496.     # if the current line is a comment, we have to check some
  497.     # special cases
  498.     if {[string index $next 0] == "\#"} {
  499.     set p [prevLineStart $beg]
  500.     if {[catch {set p [search -s -f 0 -r 1 -i 0 -m 0 "^\[ \t\]*\[^ \t\r\n\]" \
  501.       [pos::math $beg - 1]]}]} {
  502.         # check for search bug at beginning of file.
  503.         if {[pos::compare $p == [minPos]]} {
  504.         if {[getText [minPos] [pos::math [minPos] + 2]] == "\#\#"} {
  505.             if {([string range $next 0 1] != "\#\#")} {
  506.             return 1
  507.             } else {
  508.             return 0
  509.             }
  510.         }
  511.         }
  512.         return 0
  513.     }
  514.     set prev [pos::math [lindex $p 1] - 1]
  515.     set p [lindex $p 0]
  516.     if {[lookAt $prev] != "\#" || ($beg == [minPos])} {
  517.         # not a comment, so indent with code
  518.     } else {
  519.         set lwhite [posX $prev]
  520.         # it's a comment
  521.         if {[getText $prev [pos::math $prev + 2]] == "\#\#" && \
  522.           [lookAt [pos::math $prev + 2]] != "\#" \
  523.           && ([string range $next 0 1] != "\#\#")} {
  524.         # it's a comment paragraph
  525.         incr lwhite 
  526.         }
  527.     }
  528.     }
  529.     set next [string index $next 0]
  530.     if {![info exists lwhite]} {
  531.     if {![catch {search -s -f 0 -r 1 -i 0 -m 0 "^\[ \t\]*\[^\# \t\r\n\]" [pos::math $beg - 1]} lst]} {
  532.         # Find the last non-comment line and get its leading whitespace    
  533.         set lwhite [posX [pos::math [lindex $lst 1] - 1]]
  534.         set pe1 [lookAt [pos::math $beg - 2]]
  535.         set lst [lindex $lst 0]
  536.         set lastC [lookAt [lindex [search -s -f 0 -r 1 -i 0 -m 0 "\[^ \t\r\n\]" [pos::math [nextLineStart $lst] - 1]] 0]]
  537.         if {$next == "\}"} {
  538.         incr lwhite $indent_amounts(-2)
  539.         set pe2 [lookAt [pos::math [prevLineStart $beg] - 2]]
  540.         if {$pe1 == "\\"} {
  541.             incr lwhite $indent_amounts(1)
  542.         } else {
  543.             if {$pe2 == "\\"} {
  544.             incr lwhite $indent_amounts(-1)
  545.             }
  546.         }
  547.         if {$lastC == "\{"} {incr lwhite $indent_amounts(2)}    
  548.         } else { 
  549.         if {$pe1 == "\\"} {
  550.             if {[lookAt [pos::math [prevLineStart $beg] - 2]] != "\\"} {
  551.             incr lwhite $indent_amounts($indentSlashEndLines)
  552.             }
  553.         } else {
  554.             if {$lastC == "\{"} {incr lwhite $indent_amounts(2)}    
  555.             if {[lookAt [pos::math $lst - 2]] == "\\"} {
  556.             incr lwhite $indent_amounts(-$indentSlashEndLines)
  557.             }
  558.         }
  559.         }
  560.     } else {
  561.         # basically failed in all the above, so keep current indentation
  562.         set lwhite [posX [text::firstNonWsLinePos $beg]]
  563.     }
  564.     }
  565.     return [expr {$lwhite > 0 ? $lwhite : 0}]
  566. }
  567.  
  568. ## 
  569.  # -------------------------------------------------------------------------
  570.  #   
  571.  # "Tcl::indentLine" --
  572.  #  
  573.  #  Indentation for Tcl mode.  Better and faster than the generic procedure
  574.  # -------------------------------------------------------------------------
  575.  ##
  576. proc Tcl::indentLine {} {
  577.     set beg [lineStart [getPos]]
  578.     set text [getText $beg [nextLineStart $beg]]
  579.     regexp "^\[ \t\]*" $text white
  580.     set next [pos::math $beg + [string length $white]]
  581.     set lwhite [Tcl::correctIndentation [getPos] [getText $next [pos::math $next + 2]]]
  582.     
  583.     set lwhite [text::indentOf $lwhite]
  584.     if {$white != $lwhite} {
  585.     replaceText $beg $next $lwhite
  586.     }
  587.     goto [pos::math $beg + [string length $lwhite]]
  588. }
  589. # ◊◊◊◊ Tcl Menu support ◊◊◊◊ #
  590.  
  591. proc procs::reformatEnclosing {pos} {
  592.     set p [procs::findEnclosing $pos "proc|((itcl::)?(body|configbody))" 1]
  593.     eval select $p
  594.     ::indentRegion
  595. }
  596.  
  597. proc procs::loadEnclosing {pos} {
  598.     if {[catch {procs::findEnclosing $pos "proc|((itcl::)?(body|configbody))" 1} p]} {
  599.     evaluateLine $pos
  600.     } else {
  601.     eval select $p
  602.     uplevel \#0 evaluate    
  603.     }
  604.     goto $pos
  605. }
  606.  
  607. proc procs::findDefinition {} {
  608.     if {[llength [winNames]] && [string length [set sel [getSelect]]]} {
  609.     set func [listpick -L $sel -p {Proc?} [lsort -ignore [info procs]]]
  610.     } else {
  611.     set func [listpick -p {Proc?} [lsort -ignore [info procs]]]
  612.     }
  613.     
  614.     editMark [procs::find $func] $func
  615. }
  616.  
  617. proc insertMenuCodes {} {
  618.     insertText [prompt::getAKey]
  619. }
  620.  
  621. proc insertBindingCodes {} {
  622.     beep
  623.     keyCode
  624. }
  625.  
  626.  
  627. ## 
  628.  # -------------------------------------------------------------------------
  629.  # 
  630.  # "insertDivider" --
  631.  # 
  632.  #  Modified from Vince's original to allow you to just select part of
  633.  #  an already written comment and turn it into a Divider. -trf
  634.  # -------------------------------------------------------------------------
  635.  ##
  636. proc insertDivider {} {
  637.     if {[isSelection]} {
  638.     set enfoldThis [getSelect]
  639.     beginningOfLine
  640.     killLine
  641.     insertText "# ◊◊◊◊ $enfoldThis ◊◊◊◊ #"
  642.     return
  643.     } 
  644.     elec::Insertion "# ◊◊◊◊ •• ◊◊◊◊ #"
  645. }
  646.  
  647. # vince's versions seems to have been left out, so here's mine -trf
  648. # If there is a selection, it get surrounded, if there is no selection,
  649. # but the cursor is touching the end of a word, it gets surrounded. 
  650. # Otherwise, we get a template (could not come up with a "stop beyond")
  651. proc surroundWithBullets {} {
  652.     if {[pos::compare [getPos] == [selEnd]]} {
  653.     set p [getPos]
  654.     backwardWord 
  655.     set sw [getPos]
  656.     forwardWord 
  657.     set ew [getPos]
  658.     goto $p
  659.     if {[pos::compare $p == $ew]} {
  660.         select $sw $ew
  661.     } 
  662.     }
  663.     if {[isSelection]} {
  664.     set enfoldThis [getSelect]
  665.     deleteSelection
  666.     insertText "•$enfoldThis•"
  667.     return
  668.     } 
  669.     insertText "••"
  670.     backwardChar
  671.     elec::Insertion "•replace-this•"
  672. }
  673. # ◊◊◊◊ Info providers ◊◊◊◊ #
  674. #===============================================================================
  675.  
  676. ## 
  677.  # -------------------------------------------------------------------------
  678.  # 
  679.  # "TclOptionTitlebar" --
  680.  # 
  681.  #  Add corresponding extension/non-extension files.
  682.  # -------------------------------------------------------------------------
  683.  ##
  684. proc Tcl::OptionTitlebar {} {
  685.     if {[package::active smarterSource]} {
  686.     set n [win::CurrentTail]
  687.     if {[set a [string first + $n]] != -1} {
  688.         return "[string range $n 0 [expr {$a -1}]][file extension $n]"
  689.     } else {
  690.         global tclExtensionsFolder
  691.         pushd $tclExtensionsFolder
  692.         set f [glob -nocomplain -path "[file root $n]+" "*[file extension $n]"]
  693.         popd
  694.         return $f
  695.     }
  696.     } else {
  697.     return ""
  698.     }
  699. }
  700.  
  701. proc Tcl::DblClick {from to shift option control} {
  702.     
  703.     # if cmd and cntrl were pressed, we look to select part of
  704.     # a combination word (less any leading dollar sign) -trf
  705.     if {$control != 0} {
  706.     set clickedPos [getPos]    
  707.     if {[lookAt $from] == "\$"} {
  708.         set from [pos::math $from + 1]
  709.     } 
  710.     set sel_start $clickedPos 
  711.     set selStartNotDetermined 1
  712.     while {$selStartNotDetermined && ([pos::math $sel_start > $from])} {
  713.         set char [lookAt $sel_start] 
  714.         if {[regexp {_} $char]} {
  715.         set sel_start [pos::math $sel_start + 1]
  716.         set selStartNotDetermined 0
  717.         } elseif {[regexp {[A-Z]} $char]} {
  718.         set selStartNotDetermined 0
  719.         } else {
  720.         set sel_start [pos::math $sel_start -1]
  721.         } 
  722.     }
  723.     set sel_end   $clickedPos 
  724.     set selEndNotDetermined 1
  725.     while {$selEndNotDetermined && ([pos::math $sel_end <= $to])} {
  726.         set char [lookAt $sel_end] 
  727.         if {[regexp "\[A-Z_ \t\r\]" $char]} {
  728.         set selEndNotDetermined 0
  729.         } else {
  730.         set sel_end [pos::math $sel_end + 1]
  731.         } 
  732.     }
  733.     select $sel_start $sel_end 
  734.     return
  735.     } 
  736.     
  737.     # otherwise, we try to impart some extra info
  738.     select $from $to
  739.     
  740.     if {[catch {Tcl::DblClickHelper [getSelect]}]} {
  741.     message "No docs $shift $control $option"
  742.     }
  743. }
  744.  
  745.  
  746. # Now finds commands in Alpha Commands,
  747. # which has a <cr> immediately after them, e.g. beep, ticks.
  748. proc Tcl::DblClickHelper {text} {
  749.     global HOME auto_index auto_path
  750.     # Is it a loadable proc?
  751.     if {[string length [set f [procs::find $text]]]} {
  752.     if {[editMark $f $text]} {
  753.         # some marking schemes commonly used for Tcl modes
  754.         goto [lindex [search -s -f 1 -r 1 -m 0 -- "proc\[ \t\]+${text}" [minPos]] 0]
  755.     }
  756.     return
  757.     }
  758.     
  759.     if {[info exists "auto_index($text)"]} {
  760.     if {[editMark "$auto_index($text)" $text]} {
  761.         # some marking schemes commonly used for Tcl modes
  762.         goto [lindex [search -s -f 1 -r 1 -m 0 -- "proc\[ \t\]+${text}" [minPos]] 0]
  763.     }
  764.     return
  765.     }
  766.     # Is it a built-in Alpha command?
  767.     set lines [grep "^• $text\( |\$)" [file join $HOME Help "Alpha Commands"]]
  768.     if {[string length $lines]} {
  769.     if {[catch {editMark [file join $HOME Help "Alpha Commands"] $text}]} {
  770.         # mark failed for some reason, but we have the line number
  771.         # anyway.
  772.         file::openQuietly [file join $HOME Help "Alpha Commands"]
  773.         goto [rowColToPos [string trimright [lindex [lindex [split $lines "\n"] 1] 3] :] 0]
  774.     }
  775.     setWinInfo read-only 1
  776.     return
  777.     }
  778.     # Is it a core Tcl command?
  779.     set lines [grep "^     $text -" [file join $HOME Help "Tcl Commands"]]
  780.     if {[string length $lines]} {
  781.     if {[catch {editMark [file join $HOME Help "Tcl Commands"] $text}]} {
  782.         # mark failed for some reason, but we have the line number
  783.         # anyway.
  784.         file::openQuietly [file join $HOME Help "Tcl Commands"]
  785.         goto [rowColToPos [string trimright [lindex [lindex [split $lines "\n"] 1] 3] :] 0]
  786.     }
  787.     setWinInfo read-only 1
  788.     return
  789.     }
  790.     # Is it a global variable?
  791.     if {[llength [info globals [string trimleft $text {$}]]]==1} {
  792.     showVarValue [string trimleft $text {$}]
  793.     return
  794.     }
  795.     # (becoming desperate) is it a mark in the current file?
  796.     if {[lsearch [getNamedMarks -n] ${text}] != -1} {
  797.     gotoMark $text
  798.     return
  799.     }
  800.     error ""
  801. }
  802.  
  803. #############################################################################
  804. #  Report the current value of a global variable, chosen interactively
  805. #  from a list of all active variables.
  806. #
  807. #  If the variable is an array, or its value is too big to fit in an 
  808. #  alertnote, then its contents are listed in a new window, otherwise 
  809. #  the variable's value is displayed in an alertnote.
  810. #
  811. proc getVarValue {} {
  812.     if {[catch {getText [getPos] [selEnd]} def]} {set def ""}
  813.     set var [getVarFromList $def]
  814.     if {[string length $var] == 0} return
  815.     showVarValue $var
  816. }
  817.  
  818. if {[info tclversion] < 8.0} {
  819.     
  820.     proc getVarFromList {{def ""}} {
  821.     return [listpick -p {Which var?} -L $def [lsort -ignore [info globals]]]
  822.     }
  823.     
  824. } else {
  825.     
  826.     proc getVarFromList {{def ""}} {
  827.     set ns "[namespace qualifiers $def]"
  828.     set def [namespace tail $def]
  829.     
  830.     set items {}
  831.     foreach var [info vars "${ns}::*"] {
  832.         lappend items [namespace tail $var]
  833.     }
  834.     foreach space [namespace children $ns] {
  835.         lappend items "[namespace tail $space]::"
  836.     }
  837.     
  838.     set items [concat "::" [lsort -ignore $items]]
  839.     set var [listpick -p "Which var in namespace ${ns}::?" -L $def $items]
  840.     if {$var == "::"} {
  841.         set var [getVarFromList $ns]
  842.     } elseif {[namespace qualifiers $var] != ""} {
  843.         set var [getVarFromList "${ns}::${var}"]
  844.     } else {
  845.         set var "${ns}::${var}"
  846.     }
  847.     return $var
  848.     }
  849. }
  850.  
  851. #############################################################################
  852. #  Report the current value of a global variable, chosen interactively
  853. #  from a list of all active variables.
  854. #
  855. #  If the variable is an array, or its value is too big to fit in an 
  856. #  alertnote, then its contents are listed in a new window, otherwise 
  857. #  the variable's value is displayed in an alertnote.
  858. #
  859. proc showVarValue {var} {
  860.     global $var
  861.     if {![array exists $var]} {
  862.         viewValue $var [set $var]
  863.     } else {
  864.     new -n "* $var *" -info [listArray $var]
  865.     # if 'shrinkWindow' is loaded, call it to trim the output window.
  866.     catch {shrinkWindow 2}
  867.     }
  868.  
  869. #############################################################################
  870. #  List the name and value of each element of the array $arrName.
  871. #  (Convenient to use as a shell command.)
  872. #
  873. proc listArray {arrName} {
  874.     global $arrName
  875.     if {[array exists $arrName]} {
  876.     set lines {}
  877.         foreach nm [array names $arrName] {
  878.             lappend lines "\"$nm\"\t\{[set ${arrName}($nm)]\}"
  879.         }
  880.         return [join $lines \r]
  881.     } else {
  882.         alertnote "\"$arrName\" doesn't exist in this context"
  883.     }
  884. }
  885.  
  886. # ◊◊◊◊ Marking ◊◊◊◊ #
  887.  
  888. ## 
  889.  # -------------------------------------------------------------------------
  890.  #     
  891.  # "Tcl::parseFuncs" --
  892.  #    
  893.  # This proc is called by the "braces"    pop-up.    It returns a dynamically
  894.  # created, alphabetical, list of "pseudo-marks".
  895.  #    
  896.  #    Author:    Tom Fetherston
  897.  # -------------------------------------------------------------------------
  898.  ## called by the "{}" button
  899. proc Tcl::parseFuncs {} {
  900.     global TclmodeVars
  901.     set end [maxPos]
  902.     set pos [minPos]
  903.     set l {}
  904.     set markExpr "^\[ \t\]*(itcl(::|_))?(class|body|proc|method|(config)?body)\[ \t\]"
  905.     set appearanceList {}
  906.     while {![catch {search -s -f 1 -r 1 -m 0 -i 0 "$markExpr" $pos} res]} {
  907.     set start [lindex $res 0]
  908.     set end [nextLineStart $start]
  909.     set t [getText $start $end]
  910.     append t "\}"
  911.     set argLabel {}
  912.     regsub "^itcl(::|_)" [lindex $t 0] "" what
  913.     switch -- [lindex $t 0] {
  914.         "proc" {
  915.         append argLabel [set word [lindex $t 1]]
  916.         #get the list of arguments
  917.         set argsList [lindex $t 2]
  918.         if {[llength $argsList] > 0} {
  919.             append argLabel " \{"
  920.             foreach arg $argsList {
  921.             if {[llength $arg] == 2 } {
  922.                 append argLabel "¿"
  923.             } elseif {[set arg] != "args"} {
  924.                 append argLabel "•"
  925.             } else {
  926.                 append argLabel "…"
  927.             }
  928.             }
  929.             append argLabel "\}"                    
  930.         } 
  931.         }
  932.         default {
  933.         append argLabel [set word [lindex $t 1]]
  934.         }
  935.     }
  936.     if {[info exists cnts($word)]} {
  937.         # This section handles duplicate. i.e., overloaded names
  938.         set cnts($word) [expr {$cnts($word) + 1}]
  939.         set tailOfTag($word) " ($cnts($word) of $cnts($word))"
  940.         # we want the tag to point to its last occurence 
  941.         # because in Tcl, that proc will be 'in-force' when the
  942.         # file is loaded.
  943.         set indx($word) [lineStart [pos::math $start - 1]]
  944.     } else {
  945.         #SO do: remember the following
  946.         set cnts($word) 1
  947.         # if this is the only occurence of this proc, remember where it starts
  948.         set indx($word) [lineStart [pos::math $start - 1]]
  949.     }
  950.     #associate name and tag
  951.     set tag($word) $argLabel
  952.     
  953.     #advance pos to where we want to start the next search from
  954.     set pos $end
  955.     }
  956.     
  957.     set rtnRes {}
  958.     
  959.     if {[info exists indx]} {
  960.     foreach hn [lsort -ignore [array names indx]] {
  961.         set next [nextLineStart $indx($hn)]
  962.         set completeTag [set tag($hn)]
  963.         if {[info exists tailOfTag($hn)]} {
  964.         append completeTag [set tailOfTag($hn)]
  965.         }
  966.         
  967.         lappend rtnRes $completeTag $next
  968.     }
  969.     }
  970.     return $rtnRes 
  971. }
  972.  
  973. # called by the "M" button
  974. proc Tcl::MarkFile {} {
  975.     global structuralMarks
  976.     set end [maxPos]
  977.     set pos [minPos]
  978.     set l {}
  979.     if {$structuralMarks} {
  980.     set markExpr {^;?[     ]*(itcl(::|_))?(class|namespace eval|proc|method|(config)?body|# ◊◊◊◊)[     ]}
  981.     } else {
  982.     set markExpr {^;?[     ]*(itcl(::|_))?(class|namespace eval|proc|method|(config)?body)[     ]}
  983.     }
  984.     set class ""
  985.     set hasMarkers 0
  986.     while {![catch {search -s -f 1 -r 1 -m 0 -i 0 "$markExpr" $pos} res]} {
  987.     set start [lindex $res 0]
  988.     set end [nextLineStart $start]
  989.     set t [string trim [getText $start $end] ";"]
  990.     append t "\}"
  991.     if {[catch {lindex $t 0}]} {
  992.         # wasn't a well formed list
  993.         set pos $end
  994.         continue
  995.     }
  996.     regsub "^itcl(::|_)" [lindex $t 0] "" what
  997.     switch -glob $what {
  998.         "proc" -
  999.         "configbody" { set text [lindex $t 1] }
  1000.         "method" { set text ${class}::[lindex $t 1] }
  1001.         "body" { 
  1002.         regexp {[a-zA-Z_][a-zA-Z_/0-9]*::[a-zA-Z_][a-zA-Z_/0-9]* } \
  1003.           "[lindex $t 1] " text
  1004.         }
  1005.         "namespace" {
  1006.         set ns [lindex $t 2]
  1007.         if {[regexp {[^a-zA-Z0-9]} $ns]} {
  1008.             set pos $end
  1009.             continue
  1010.         }
  1011.         set text "${ns} 111" 
  1012.         }
  1013.         "*class" { 
  1014.         set class [lindex $t 1]
  1015.         set text "${class} 000" 
  1016.         }
  1017.         "#" { 
  1018.         regexp "# ◊◊◊◊ (.*) ◊◊◊◊" $t all text
  1019.         if {[regexp "^(    )|(    )# ◊◊◊◊ " $t]} {
  1020.             set text " •$text"
  1021.         } else {
  1022.             set text "•$text"
  1023.         }                
  1024.         set hasMarkers 1
  1025.         }
  1026.     }
  1027.     set pos $end
  1028.     if {$structuralMarks} {
  1029.         lappend asEncountered $text
  1030.         set arr inds
  1031.     } else {
  1032.         if {[string index $t 0] == ";"} {
  1033.         set arr iinds
  1034.         } else {
  1035.         set arr inds
  1036.         }
  1037.     }
  1038.     set ${arr}($text) [lineStart [pos::math $start - 1]]
  1039.     }
  1040.     
  1041.     set already ""
  1042.     set class "#"
  1043.     foreach arr {inds iinds} {
  1044.     if {[info exists $arr]} {
  1045.         if {$arr == "iinds"} {
  1046.         setNamedMark "-" 0 0 0
  1047.         }
  1048.         if {$structuralMarks} {
  1049.         set order $asEncountered
  1050.         } else {
  1051.         set order [lsort -ignore [array names $arr]]
  1052.         }
  1053.         foreach f $order {
  1054.         if {[set el [set ${arr}($f)]] != 0} {
  1055.             set next [nextLineStart $el]
  1056.         } else {
  1057.             set next 0
  1058.         } 
  1059.         
  1060.         if { [string first "000" $f] != -1 } {
  1061.             set ff "Class '[set class [lindex $f 0]]'"
  1062.         } elseif { [string first "111" $f] != -1 } {
  1063.             set ff "Namespace '[set class [lindex $f 0]]'"
  1064.         } elseif { [string first "${class}::" $f] == 0 } {
  1065.             set ff [string range $f [string length $class] end]
  1066.         } else {
  1067.             set ff $f
  1068.         }
  1069.         while { [lsearch -exact $already $ff] != -1 } {
  1070.             set ff "$ff "
  1071.         }
  1072.         lappend already $ff
  1073.         if {$hasMarkers && ![string match "•*" $ff] } {
  1074.             set ff " $ff"
  1075.         } 
  1076.         setNamedMark $ff $el $next $next
  1077.         }
  1078.     }
  1079.     }
  1080. }
  1081.  
  1082. # ◊◊◊◊ Misc. ◊◊◊◊ #
  1083.  
  1084. ## 
  1085.  # -------------------------------------------------------------------------
  1086.  # 
  1087.  # "bind::tclContinueComment" --
  1088.  # 
  1089.  #  exploits a "feature" in the code that makes a new line a comment whenever 
  1090.  #  you are 'inside' a comment. This proc puts a pound sign at the end of the 
  1091.  #  current line, backsteps, and creates a new line. With the pound sign 
  1092.  #  present you are considered to be in a comment, so the bind::CarriageReturn 
  1093.  #  in the proc, and any subsequent bind::CarriageReturn called by a press of  
  1094.  #  the return key will provide another comment line automatically until the 
  1095.  #  pound sign at the end of the line is removed (killLine is handy for this).
  1096.  # -------------------------------------------------------------------------
  1097.  ##
  1098. proc bind::tclContinueComment {} {
  1099.     insertText {#}
  1100.     backwardChar
  1101.     bind::CarriageReturn
  1102.     deleteChar
  1103. }
  1104. Bind '\r' <c> bind::tclContinueComment Tcl
  1105.  
  1106. proc evaluateLine { pos } {
  1107.     goto $pos
  1108.     beginningLineSelect
  1109.     endLineSelect
  1110.  
  1111.     uplevel \#0 evaluate
  1112. }
  1113.  
  1114. #◊◊◊◊> 
  1115.  
  1116. evaluateRemoteSynchronise
  1117.  
  1118.